package com.tangding.net.coder;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.tangding.common.logx.LogHelp;
import com.tangding.common.utils.Utils;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;

/**
 * @description 包头6位保存真实数据长度
 * 
 *              [0,0,x,y,0,0] 真实数据长度为：x * 100 + y
 * 
 *
 * @author Ranger
 * @version 2014-4-29_上午9:37:59
 *
 */
@Scope("prototype")
@Component("gameCoder")
public class GameCoder extends ByteToMessageCodec<byte[]> {

	int decodeTimesLimit = 100;// 递归次数限制

	@Override
	protected void decode(ChannelHandlerContext ch, ByteBuf in, List<Object> reader) throws Exception {
		analyzeData(in, reader, 0);
	}

	private void analyzeData(ByteBuf in, List<Object> reader, int times) {
		if (times >= decodeTimesLimit) {
			LogHelp.doLogApp("decoder more than " + decodeTimesLimit + " times...");
			clear(in);// 清理buf
			return;
		}

		List<Byte> headList = getHeadList(in);
		if (headList == null) {
			return;
		}

		if (!isStartWithHeadStruct(in)) {
			clear(in);
			return;
		}
		
		if (hasFullData(headList, in)) {
			long packLength = getRealPackLength(headList);
			in.skipBytes(headList.size() + 4);
			byte[] cache = new byte[(int) packLength];
			in.readBytes(cache, 0, (int) packLength);
			reader.add(cache);
			in.markReaderIndex();
			if (in.readableBytes() > 0) {// 还有残留包体
				if (isStartWithHeadStruct(in)) {
					analyzeData(in, reader, times + 1);
				} else {
					clear(in);
					return;
				}
			}
		} else {
			in.resetReaderIndex();
			return;
		}
	}

	public boolean hasFullData(List<Byte> headList, ByteBuf data) {
		long length = getRealPackLength(headList);
		if (length + headList.size() + 4 <= data.readableBytes()) {// 有完整的包//
			return true;
		} else {// 没有完整的包//
			return false;
		}
	}

	public List<Byte> getHeadList(ByteBuf buf) {
		long readableLength = buf.readableBytes();
		if (readableLength <= 5) {
			return null;
		}

		// 跳过包头两个字节指定结构
		buf.skipBytes(2);

		List<Byte> headList = new ArrayList<>();
		boolean findHeadTail = false;// 记录是否找到包头结尾//
		for (int i = 2; i < readableLength; i++) {
			byte d = buf.readByte();
			if (d == 100) {
				if (i < readableLength - 1 && buf.readByte() == 100)// 包头结尾//
				{
					findHeadTail = true;
					break;
				} else {
					buf.resetReaderIndex();
					return null;
				}
			} else {
				headList.add(d);
			}
		}
		buf.resetReaderIndex();
		if (findHeadTail) {
			return headList;
		}
		return null;
	}

	public long getRealPackLength(List<Byte> headList) {
		long length = 0;
		for (int i = 0; i < headList.size(); i++) {
			byte d = headList.get(i);
			length += d * (long) Math.pow(100, headList.size() - 1 - i);
		}
		return length;
	}

	private void clear(ByteBuf buf) {
		buf.clear();
		buf.markReaderIndex();
		buf.resetReaderIndex();
		buf.markWriterIndex();
		buf.resetWriterIndex();
	}

	// 检查数据是否是包头结构开头
	private boolean isStartWithHeadStruct(ByteBuf buf) {
		if (buf.readByte() != 100 || buf.readByte() != 100) {// 开始不是以[100,100]的格式开头
			buf.resetReaderIndex();
			return false;
		}
		buf.resetReaderIndex();
		return true;
	}
	
	@Override
	protected void encode(ChannelHandlerContext ch, byte[] data, ByteBuf out) throws Exception {
		out.writeBytes(addHead(data));
	}


	// 给数据添加头部
	private byte[] addHead(byte[] data) {
		LinkedList<Byte> headList = new LinkedList<Byte>();
		headList.addFirst((byte) 100);
		headList.addFirst((byte) 100);
		pushHeadByte(headList, data.length);
		headList.addFirst((byte) 100);
		headList.addFirst((byte) 100);
		byte[] head = new byte[headList.size()];
		for (int i = 0; i < headList.size(); i++) {
			head[i] = headList.get(i);
		}
		return Utils.combineArray(head, data);
	}

	public void pushHeadByte(LinkedList<Byte> head, long leftLengthValue) {
		if (leftLengthValue == 0) {
			return;
		}

		head.addFirst((byte) (leftLengthValue % 100));
		pushHeadByte(head, leftLengthValue / 100);
	}
}